package fr.lip6.meta.ple.plextraction.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.gmt.modisco.java.Model;
import org.eclipse.gmt.modisco.java.NamedElement;

import fr.lip6.meta.ple.generation.aspectj.ProcessConstraintAJ;
import fr.lip6.meta.ple.generation.aspectj.ProductLineConstructionAJ;
import fr.lip6.meta.ple.generation.aspectj.ReadXmiAJ;
import fr.lip6.meta.ple.generation.fh.java.ProcessConstraintFHJava;
import fr.lip6.meta.ple.generation.fh.java.ProductLineConstructionFHJava;
import fr.lip6.meta.ple.generation.fh.java.ReadXmiFHJava;
import fr.lip6.meta.ple.generation.strategy.GenerationContext;

public class Configuration implements Serializable {
	private static final long serialVersionUID = 1L;
	private static Configuration uniqueInstance = null;
	private Map<String, String> parameters;
	private GenerationContext generationContext = null;
	private Map<String, Model> models = null;
	private Map<String, NamedElement> imports = null;

	/*
	 * Type of Java extension output method
	 * Default: FeatureHouse
	 */
	private ExtensionType extensionType = ExtensionType.FH;
	
	private Configuration() {
		parameters = new HashMap<String, String>();
	}
	
	public static Configuration getInstance() {
		if (uniqueInstance == null)
			uniqueInstance = new Configuration();
		
		return uniqueInstance;
	}
	
	public String getParameterValue(String param) {
		return parameters.get(param);
	}
	
	public void setParameterValue(String param, String value) {
			parameters.put(param, value);
	}
	
	public String removeParameter(String param) {
		return parameters.remove(param);
	}

	public GenerationContext getGenerationContext() {
		return generationContext;
	}

	public void setGenerationContext(GenerationContext generationContext) {
		this.generationContext = generationContext;
	}
	
	public Map<String, Model> getModels() {
		return models;
	}

	public void setModels(Map<String, Model> models) {
		this.models = models;
	}

	public ExtensionType getExtensionType() {
		return extensionType;
	}

	public void setExtensionType(ExtensionType extension) {
		this.extensionType = extension;
		
		/*
		 * initialization of generation context
		 */
		
		switch(extension) {
		// AspectJ
		case AJ:
			ReadXmiAJ readXmiAJ = new ReadXmiAJ();
			ProductLineConstructionAJ productLineConstructionAJ = new ProductLineConstructionAJ();
			
			productLineConstructionAJ.setReadXmi(readXmiAJ);
			
			generationContext = new GenerationContext(
					new ProcessConstraintAJ(),
					productLineConstructionAJ,
					readXmiAJ
				);
			break;
		// FeatureHouse
		case FH:
			ReadXmiFHJava readXmi = new ReadXmiFHJava();
			ProductLineConstructionFHJava productLineConstructionFHJava = new ProductLineConstructionFHJava();
			
			productLineConstructionFHJava.setReadXmi(readXmi);
			
			generationContext = new GenerationContext(
					new ProcessConstraintFHJava(),
					productLineConstructionFHJava,
					readXmi
				);
		default:
			break;
		}
	}

	/**
	 * Import de la configuration sauvee par la serialisation.
	 * 
	 * @param fileName
	 *            : nom du fichier sauve par la serialisation
	 * @throws IOException probleme de lecture du fichier ou de son contenu
	 */
	public static void chargerConfig(String fileName) throws IOException {
		FileInputStream fis = new FileInputStream(fileName);
		ObjectInputStream ois = new ObjectInputStream(fis);
		try {
			Configuration config = (Configuration) ois.readObject();
			uniqueInstance = config;
		} catch (ClassCastException e) {
			throw new IOException(
				"Le fichier ne contient pas une configuration.", e);
		} catch (ClassNotFoundException e) {
			throw new IOException(
				"JVM does not know the type Configuration.", e);
		}
	}

	/**
	 * Export de la configuration par la sérialisation
	 * @param le nom du fichier a charger (en convention {@link File})
	 * @throws IOException En cas de problame d'acriture dans ce fichier.
	 */
	public static void sauverConfig(String fileName, Configuration config)
			throws IOException {
		FileOutputStream fos = new FileOutputStream(fileName);
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(config);
		fos.close();
	}
}